package com.ugoodtech.mdcc.client.service.impl;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.map.MapUtil;
import cn.hutool.http.HttpConfig;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSON;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.alibaba.druid.support.json.JSONUtils;
import com.ugoodtech.mdcc.client.service.WeChatCallbackService;
import com.ugoodtech.mdcc.client.wechat.WeChatApi;
import com.ugoodtech.mdcc.core.model.entity.UnionIdOpenId;
import com.ugoodtech.mdcc.core.model.entity.UnionIdOpenIdExample;
import com.ugoodtech.mdcc.core.model.entity.UnionIdOpenIdExample.Criteria;
import com.ugoodtech.mdcc.core.model.entity.Users;
import com.ugoodtech.mdcc.core.model.entity.UsersExample;
import com.ugoodtech.mdcc.core.model.mapper.UnionIdOpenIdMapper;
import com.ugoodtech.mdcc.core.model.mapper.UsersMapper;
import com.ugoodtech.mdcc.core.model.mapper.ext.UnionIdOpenIdExtMapper;
import com.ugoodtech.mdcc.core.service.impl.WechatPushServiceImpl;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

/**
 * Created by Xiangcheng Li
 *
 * @author Xiangcheng Li
 */

@Service
@Slf4j
public class WeChatCallbackServiceImpl implements WeChatCallbackService {


    @Autowired
    private WeChatApi weChatApi;

    @Autowired
    private WechatPushServiceImpl wechatPushService;
    @Autowired
    private UnionIdOpenIdExtMapper unionIdOpenIdMapper;
    @Autowired
    private UsersMapper usersMapper;

    @Value("${wechat.appID}")
    private String weChatAppId;

    @Value("${wechat.appSecret}")
    private String weChatSecret;

    private String sToken = "01d5c6faf395e322d783cd31d4e84480";
    private String aeskey = "ChoOlgwhIkmuTMH1fyvsjr13jLj3Q1mxSe8T0WBvXX0";

    /**
     * 校验url
     * @param token
     * @param echoStr
     * @param timestamp
     * @param nonce
     * @param msgSign
     * @return
     */
    @Override
    public String verifyUrl(String echoStr, String timestamp, String nonce, String msgSign){
        log.info("{}, {}, {}, {}, {}, {}, {}", weChatAppId, sToken, aeskey, msgSign, timestamp,
            nonce, echoStr);
        return weChatApi.verifyUrl(weChatAppId, sToken, aeskey, msgSign, timestamp, nonce, echoStr);
    }



    /**
     * 设置公众号菜单
     *
     * @param link
     * @return
     */
    @Override
    public void addMenu(String link){
        String accessToken = wechatPushService.getAccess_token();
        String weChatUrl = "https://api.weixin.qq.com/cgi-bin/menu/create?access_token=" + accessToken;
        URLConnection urlConnection = null;
        InputStream inputStream = null;
        PrintWriter out = null;
        Map<String, Object> paramsMap = new HashMap<>();
        Map<String, Object> buttonMap = new HashMap<>();
        buttonMap.put("type", "view");
        buttonMap.put("name", "漆星服务");
        buttonMap.put("url", "link");
        paramsMap.put("button", buttonMap);
        try {
            URL url = new URL(weChatUrl);
            urlConnection = url.openConnection();
            urlConnection.setDoOutput(true);
            urlConnection.setDoInput(true);
            out = new PrintWriter(urlConnection.getOutputStream());

            System.out.println(new org.json.JSONObject(paramsMap).toString());
            out.print(new org.json.JSONObject(paramsMap).toString());
            out.flush();
            // 定义待写入数据的内容类型，我们设置为application/x-www-form-urlencoded类型
            urlConnection.setRequestProperty("content-type", "application/json");
            inputStream = urlConnection.getInputStream();
            String encoding = urlConnection.getContentEncoding();
            String body = IOUtils.toString(inputStream, encoding);

            log.info("设置菜单结果 {}", body);

        } catch (IOException e) {
            System.out.println(weChatUrl + " 的请求连接失败");
        } finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                System.out.println("请求为" + weChatUrl + "输入流关闭失败");
            }
        }
    }




    public Boolean handleCallback(String encrypt, String timestamp, String nonce, String msgSign){
        log.info("handleCallback --- encrypt: {}, timestamp: {}, nonce: {}, msgSign: {}", encrypt, timestamp, nonce, msgSign);
        String content = weChatApi.handleCallBack(weChatAppId, sToken, aeskey, msgSign,
            timestamp, nonce, encrypt);
        log.info("handleCallback --- content: {}", content);
        JSONObject xmlObj = JSONUtil.parseFromXml(content);
        JSONObject contentObj = xmlObj.getJSONObject("xml");


        // <xml><ToUserName><![CDATA[gh_41f207de7404]]></ToUserName>
        // <FromUserName><![CDATA[omSAT1uQKjuDA9Ed5mr8unMCdlFQ]]></FromUserName>
        // <CreateTime>1723167721</CreateTime>
        // <MsgType><![CDATA[event]]></MsgType>
        // <Event><![CDATA[subscribe]]></Event>
        // <EventKey><![CDATA[]]></EventKey>
        // </xml>
        if (Objects.equals(contentObj.getStr("Event"), "subscribe")) {
            String openId = contentObj.getStr("FromUserName");
            String responseBody = getUnionIdByOpenId(Arrays.asList(openId));

            updateUnionIdAndUserId(responseBody);

        }

        return true;
    }


    /**
     * 通过unionid获取openid
     * @param openIdList
     * @return
     */
    public String getUnionIdByOpenId(List<String> openIdList) {
        String accessToken = wechatPushService.getAccess_token();
        log.info("获取");
        String url =
            "https://api.weixin.qq.com/cgi-bin/user/info/batchget?access_token=" + accessToken;
        Map<String, Object> paramsMap = new HashMap<>();
        ArrayList<Object> userList = new ArrayList<>();
        for (String openId : openIdList) {
            Map<String, String> openIdMap = new HashMap<>();
            openIdMap.put("openid", openId);
            openIdMap.put("lang", "zh_CN");
            userList.add(openIdMap);
        }
        paramsMap.put("user_list", userList);
        log.info("openid list is, {}", JSONUtil.toJsonStr(paramsMap));
        return HttpUtil.post(url, JSONUtil.toJsonStr(paramsMap));
    }

    /**
     * 更新unionId和openid对应关系
     * @param responseBody
     * @return
     */
    public Boolean updateUnionIdAndUserId(String responseBody){
        log.info("responseBody: {}", responseBody);
        JSONObject resObj = JSONUtil.parseObj(responseBody);
        JSONArray userInfoList = resObj.getJSONArray("user_info_list");
        if (CollectionUtil.isEmpty(userInfoList)) {
            return false;
        }
        List<String> unionIdList = new ArrayList<>();
        for (int i = 0; i < userInfoList.size(); i++) {
            JSONObject userInfo = userInfoList.getJSONObject(i);
            String unionId = userInfo.getStr("unionid");
            unionIdList.add(unionId);
        }
        UnionIdOpenIdExample unionIdOpenIdExample = new UnionIdOpenIdExample();
        Criteria criteria = unionIdOpenIdExample.createCriteria();
        criteria.andUnionIdIn(unionIdList);

        List<UnionIdOpenId> unionIdOpenIds = unionIdOpenIdMapper.selectByExample(
            unionIdOpenIdExample);
        Map<String, UnionIdOpenId> unionIdToRecordMap = unionIdOpenIds.stream()
            .collect(Collectors.toMap(UnionIdOpenId::getUnionId, Function.identity()));
        List<UnionIdOpenId> toInserList = new ArrayList<>();
        for (int i = 0; i < userInfoList.size(); i++) {
            JSONObject userInfo = userInfoList.getJSONObject(i);
            String unionId = userInfo.getStr("unionid");
            String openId = userInfo.getStr("openid");
            UnionIdOpenId unionIdOpenId = unionIdToRecordMap.get(unionId);
            // 更新unionId和openid对应表
            if (Objects.isNull(unionIdOpenId)) {
                UnionIdOpenId newInsert = new UnionIdOpenId();
                newInsert.setUnionId(unionId);
                newInsert.setOpenId(openId);
                newInsert.setCreateTime(DateUtil.date());
                newInsert.setUpdateTime(DateUtil.date());
                newInsert.setDeleted(0);
                toInserList.add(newInsert);
            } else {
                if (!Objects.equals(openId, unionIdOpenId.getOpenId())) {
                    UnionIdOpenId toUpdate = new UnionIdOpenId();
                    toUpdate.setOpenId(openId);
                    toUpdate.setUpdateTime(DateUtil.date());
                    UnionIdOpenIdExample updateExample = new UnionIdOpenIdExample();
                    Criteria updateExampleCriteria = updateExample.createCriteria();
                    updateExampleCriteria.andUnionIdEqualTo(unionId);
                    unionIdOpenIdMapper.updateByExampleSelective(toUpdate, updateExample);
                }
            }
        }
        for (int i=0; i < toInserList.size(); ){

            unionIdOpenIdMapper.batchInsert(toInserList.subList(i,
                Math.min(i + 2000, toInserList.size())));
            i+= 2000;
        }
        return true;
    }

    @Override
    public Boolean getUnionIdOfOldOpenId(){
        List<Users> users = usersMapper.selectByExample(new UsersExample());
        List<String> openIdList =
            users.stream().map(Users::getOpenid).filter(Objects::nonNull).filter(StringUtils::isNotEmpty)
            .collect(Collectors.toList());
        for (int i = 0; i < openIdList.size(); i++) {
            List<String> subList = openIdList.subList(i, Math.min(i + 100, openIdList.size()));
            String responseBody = getUnionIdByOpenId(subList);
            updateUnionIdAndUserId(responseBody);
        }

        return true;
    }
}
